import { Injectable, Injector } from '@angular/core';
import {
    HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse,
    HttpSentEvent, HttpHeaderResponse, HttpProgressEvent, HttpResponse, HttpUserEvent,
} from '@angular/common/http';
// import { Storage } from '@ionic/storage';
import { Observable, of, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { mergeMap } from 'rxjs/operators';
import { Utils } from '../../providers/common/utils';
import { CONFIG } from '../../app/app.config';
// import { Md5 } from 'md5-typescript';
import { ToastProvider } from '../../providers/common/toastUtil';
import { LoadingProvider } from '../../providers/common/loadingUtil';

declare const webpackGlobalVars: any;

class Pagination {
    count: number;
    currentPage: number;
    nextPage: number;
    prevPage: number;
    totalCount: number;
}

export class Meta {
    pagination = new Pagination();
}

export interface IResponse {
    status: boolean;
    result: any;
    meta?: Meta
}

/**
 * 默认HTTP拦截器，其注册细节见 `app.module.ts`
 */
@Injectable()
export class DefaultInterceptor implements HttpInterceptor {
    constructor(private injector: Injector, private toastProvider: ToastProvider, private loadingProvider: LoadingProvider) {
    }

    // private goTo(url: string) {
    //     setTimeout(() => this.injector.get(Router).navigateByUrl(url));
    // }

    private handleData(event: HttpResponse<any> | HttpErrorResponse): Observable<any> {
        // 可能会因为 `throw` 导出无法执行 `_HttpClient` 的 `end()` 操作
        // this.injector.get(_HttpClient).end();
        // 业务处理：一些通用操作
        setTimeout(() => {
            if (Utils.isNotEmpty(LoadingProvider.loading)) {
                this.loadingProvider.dismiss();
                LoadingProvider.loading = null;
            }
        });

        switch (event.status) {
            case 200:
                // 业务层级错误处理，以下是假定restful有一套统一输出格式（指不管成功与否都有相应的数据格式）情况下进行处理
                // 例如响应内容：
                //  错误内容：{ status: 1, msg: '非法参数' }
                //  正确内容：{ status: 0, response: {  } }
                // 则以下代码片断可直接适用
                if (event instanceof HttpResponse) {
                    const body: any = event.body;
                    if (body && body.status === CONFIG.SUCCESS_CODE) {
                        // 重新修改 `body` 内容为 `response` 内容，对于绝大多数场景已经无须再关心业务状态码
                        // return of(new HttpResponse(Object.assign(event, { body: body.response })));
                        // 或者依然保持完整的格式
                        return of(event);
                    } else {
                        this.toastProvider.error(body.description);
                        // 继续抛出错误中断后续所有 Pipe、subscribe 操作，因此：
                        // this.http.get('/').subscribe() 并不会触发
                        // return throwError({ description: body.description });
                        // return of(event);
                    }
                }
                break;
            case 401: // 未登录状态码
                // this.tokenService.clear();
                // this.goTo('/passport/login');
                this.toastProvider.error('登陆信息已过期，请重试');
                break;
            // return of(event);
            case 403:
                // this.tokenService.clear();
                // this.goTo('/passport/login');
                // 无操作权限
                this.toastProvider.error('当前用户无权限执行此操作');
                break;
            case 404:
            case 413:
                // 目前为文件过大
                if (event instanceof HttpErrorResponse) {
                    this.toastProvider.error(event.message);
                }
                break;
            case 500:
                if (event instanceof HttpResponse) {
                    const body: any = event.body;
                    if (body && body.exception === 'com.netflix.zuul.exception.ZuulException') {
                        this.toastProvider.error('系统正在维护中，请你稍后再试');
                    }
                }
                // this.goTo(`/${event.status}`);
                break;
            default:
                if (event instanceof HttpErrorResponse) {
                    console.warn('未可知错误，大部分是由于后端不支持CORS或无效配置引起', event);
                    // this.msg.error(event.message);
                }
                break;
        }
        return of(event);
    }

    intercept(req: HttpRequest<any>, next: HttpHandler):
        Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
        // 统一加上服务端前缀
        const date = new Date();
        const uuid = Utils.UUID();
        const LOGIN_DATA = JSON.parse(sessionStorage.getItem('LOGIN_DATA'));
        const USER_AGENT = window.navigator.userAgent.toLowerCase();
        let url = req.url;
        // CONFIG.BASIC_CONFIGS.LOADING_MESSAGE
        if (Utils.isEmpty(LoadingProvider.loading) && url.indexOf('access') === -1) this.loadingProvider.loading('open', CONFIG.BASIC_CONFIGS.LOADING_MESSAGE);
        if (!url.startsWith('https://') && !url.startsWith('http://')) {
            url = encodeURI(webpackGlobalVars.url + url);
        }

        let requestHead = CONFIG.ENV.headers;
        if (url.indexOf('/files') >= 0 || url.indexOf('/upload') >= 0 || url.indexOf('/import') >= 0) {
            requestHead = {};
        } else {
            requestHead['timestamp'] = '' + date.getTime();
            requestHead['uuid'] = uuid;
            requestHead['Content-Type'] = 'application/json;charset=UTF-8';
            requestHead['pragma'] = 'no-cache';
            requestHead['Cache-Control'] = 'no-store, must-revalidate';
            requestHead['Authorization'] = sessionStorage.getItem('temp_token_user_token');
        }

        // 添加token
        // if (this.auth.isAuthenticated()) {
        //   Object.assign(update, {
        //     setHeaders: { Authorization: this.auth.authorization }
        //   });
        // } else {
        //   return;
        // }

        const newReq = req.clone({
            url: url,
            setHeaders: requestHead
        });
        return next.handle(newReq).pipe(
            mergeMap((event: any) => {
                // 允许统一对请求错误处理，这是因为一个请求若是业务上错误的情况下其HTTP请求的状态是200的情况下需要
                if (event instanceof HttpResponse && event.status === 200) return this.handleData(event);
                // 若一切都正常，则后续操作
                return of(event);
            }),
            catchError((res: HttpErrorResponse) => {
                if (url.indexOf('access') >= 0) this.toastProvider.error('当前环境出错，请联系管理员或稍后再试');
                console.error(res);
                // 返回错误
                return throwError(res);
            })
        );
    }
}
